home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 2000-1 drscholl@users.sourceforge.net
- This is free software distributed under the terms of the
- GNU Public License. See the file COPYING for details.
-
- $Id: public.c,v 1.41 2001/02/15 08:39:45 drscholl Exp $ */
-
- #include <stdio.h>
- #ifndef WIN32
- #include <unistd.h>
- #endif
- #include <string.h>
- #include "opennap.h"
- #include "debug.h"
-
- /* static buffer for use by public/emote. these get called a lot so speed
- things up by keeping it around. there is no chance of either of these
- being called from eachother or used elsewhere so this is safe */
- static char PublicBuf[2048];
-
- /* determine if `sender' has permission to send to channel `chan' */
- static int
- check_permission (CHANNEL * chan, USER * sender)
- {
- LIST *list;
- CHANUSER *chanUser;
-
- for (list = chan->users; list; list = list->next)
- {
- chanUser = list->data;
- if (chanUser->user == sender)
- break;
- }
-
- if (!list)
- {
- log ("check_permission: fatal error, could not find %s on channel %s",
- sender->nick, chan->name);
- return -1;
- }
-
- if (sender->level < LEVEL_MODERATOR
- && (chanUser->flags & ON_CHANNEL_OPERATOR) == 0)
- {
- if (chan->flags & ON_CHANNEL_MODERATED)
- {
- if ((chanUser->flags & ON_CHANNEL_VOICE) == 0)
- {
- if (ISUSER (sender->con))
- send_cmd (sender->con, MSG_SERVER_NOSUCH,
- "permission denied: channel is moderated");
- return -1;
- }
- }
- else if (chanUser->flags & ON_CHANNEL_MUZZLED)
- {
- if (ISUSER (sender->con))
- send_cmd (sender->con, MSG_SERVER_NOSUCH,
- "permission denied: muzzled on channel");
- return -1;
- }
- }
-
- return 0;
- }
-
- /* 402 [ :<sender> ] <channel> <text> */
- /* public message to a channel */
- HANDLER (public)
- {
- CHANNEL *chan;
- USER *sender;
- LIST *list;
- char *ptr;
- char *sender_name;
- CHANUSER *chanUser;
-
- ASSERT (validate_connection (con));
- /* save the starting position of the pkt */
- ptr = pkt;
- if (pop_user_server (con, tag, &pkt, &sender_name, &sender))
- return;
- if (sender->muzzled)
- {
- if (ISUSER (con))
- send_cmd (con, MSG_SERVER_NOSUCH, "You are muzzled.");
- return;
- }
-
- /* protect against DoS attack against the windows napster client */
- if (len - (pkt - ptr) > 180)
- {
- pkt[180] = 0; /* crop the message */
- log ("public: cropped %d byte message from user %s", len,
- sender->nick);
- }
-
- /* can't use split line here because the text field is considered all
- one item */
- /* extract the channel name. NOTE: we don't use next_arg() here because
- it will strip leading space from the text being sent */
- ptr = next_arg_noskip (&pkt);
- if (!pkt)
- {
- unparsable (con);
- return;
- }
-
- /* find the channel this message is going to. look the user's joined
- channels since this should be faster than lookup in the hash table */
- if (!(chan = find_channel (sender->channels, ptr)))
- {
- if (ISUSER (con))
- send_cmd (con, MSG_SERVER_NOSUCH,
- "You are not a member of that channel");
- return;
- }
-
- if (ISSERVER (con) && chan->local)
- {
- log ("public: server %s accessed local channel %s", con->host,
- chan->name);
- return;
- }
-
- if (check_permission (chan, sender))
- return;
-
- /* relay this message to peer servers */
- if (!chan->local)
- pass_message_args (con, tag, ":%s %s %s", sender->nick, chan->name,
- pkt);
-
- /* the majority of the users in the channel will see this message, so
- form it one time */
- len = form_message (PublicBuf, sizeof (PublicBuf), MSG_SERVER_PUBLIC,
- "%s %s %s", chan->name,
- sender->cloaked ? "Operator" : sender->nick, pkt);
-
- /* send this message to everyone in the channel */
- for (list = chan->users; list; list = list->next)
- {
- chanUser = list->data;
- ASSERT (chanUser->magic == MAGIC_CHANUSER);
- if (ISUSER (chanUser->user->con))
- {
- if (sender->cloaked && chanUser->user->level > LEVEL_USER)
- send_cmd (chanUser->user->con, MSG_SERVER_PUBLIC, "%s %s %s",
- chan->name, sender->nick, pkt);
- else
- queue_data (chanUser->user->con, PublicBuf, len);
- }
- }
- }
-
- /* 824 [ :<user> ] <channel> "<text>" */
- HANDLER (emote)
- {
- CHANUSER *chanUser;
- USER *user;
- CHANNEL *chan;
- char *ptr, *av[2];
- char *sender_name;
- LIST *list;
-
- ASSERT (validate_connection (con));
- ptr = pkt; /* save initial location */
- if (pop_user_server (con, tag, &pkt, &sender_name, &user) != 0)
- return;
- if (user->muzzled)
- {
- if (ISUSER (con))
- send_cmd (con, MSG_SERVER_NOSUCH, "You are muzzled");
- return;
- }
-
- /* protect against DoS attack against the windows napster client */
- if (len - (pkt - ptr) > 180)
- {
- /* crop message */
- pkt[179] = '"';
- pkt[180] = 0;
- log ("emote: cropped %d byte message from user %s", len, user->nick);
- }
-
- if (split_line (av, sizeof (av) / sizeof (char *), pkt) < 2)
- {
- unparsable (con);
- return;
- }
-
- /* find the channel this message is going to. look the user's joined
- channels since this should be faster than lookup in the hash table */
- if (!(chan = find_channel (user->channels, av[0])))
- {
- if (ISUSER (con))
- send_cmd (con, MSG_SERVER_NOSUCH,
- "You are not a member of that channel");
- return;
- }
-
- if (ISSERVER (con) && chan->local)
- {
- log ("emote: server %s accessed local channel %s",
- con->host, chan->name);
- return;
- }
-
- if (check_permission (chan, user))
- return;
-
- /* relay to peer servers */
- if (!chan->local)
- pass_message_args (con, tag, ":%s %s \"%s\"", user->nick, chan->name,
- av[1]);
-
- /* majority of the users see the same message, so form it once */
- len = form_message (PublicBuf, sizeof (PublicBuf), tag, "%s %s \"%s\"",
- chan->name,
- user->cloaked ? "Operator" : user->nick, av[1]);
-
- /* send this message to all channel members */
- for (list = chan->users; list; list = list->next)
- {
- chanUser = list->data;
- ASSERT (chanUser->magic == MAGIC_CHANUSER);
- if (ISUSER (chanUser->user->con))
- {
- if (user->cloaked && chanUser->user->level > LEVEL_USER)
- send_cmd (chanUser->user->con, tag, "%s %s \"%s\"",
- chan->name, user->nick, av[1]);
- else
- queue_data (chanUser->user->con, PublicBuf, len);
- }
- }
- }
-
- /* queues a raw message (tag & length header is assumed to be present */
- int
- send_to_channel (char *name, char *buf, int buflen)
- {
- CHANNEL *chan;
- LIST *list;
- CHANUSER *user;
-
- /* if the Channels hash table has not been initialized yet, abort */
- if (!Channels)
- return -1;
- chan = hash_lookup (Channels, name);
- /* if nobody is in the log channel, abort */
- if (!chan)
- return -1;
- for (list = chan->users; list; list = list->next)
- {
- user = list->data;
- if (ISUSER (user->user->con))
- queue_data (user->user->con, buf, buflen);
- }
- return 0;
- }
-